package org.javahispano.javacup.tacticas_aceptadas.fpena.org.tricolor;

import java.util.ArrayList;
import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.modelo.Posicion;
import org.javahispano.javacup.modelo.SituacionPartido;

public class Util {

    public static int ITERACIONES_CRUZAR_BALON = 50;

    public static int[] getInfoMasCercano(Posicion[] lista, Posicion punto) {
        return getInfoMasCercano(lista, punto, null, false);
    }

    public static int[] getInfoMasCercano(Posicion[] lista, Posicion punto, ArrayList excluir, boolean soloDelante) {
        int dev[] = {-1, 999};
        int nDis;
        for (int n = 0; n < lista.length; n++) {
            if (excluir == null || !excluir.contains(n)) {
                if (!soloDelante || lista[n].getY() > punto.getY()) {
                    nDis = (int) lista[n].distancia(punto);
                    if (nDis < dev[1]) {
                        dev[0] = n;
                        dev[1] = nDis;
                    }
                }
            }
        }
        return dev;
    }

    public static int getGoleroRival(SituacionPartido sp) {
        for (int i = 0; i < sp.detalleJugadoresRivales().length; i++) {
            if (sp.detalleJugadoresRivales()[i].esPortero()) {
                return i;
            }
        }
        return -1;
    }

    public static double distanciaAlSegmento(Posicion n1, Posicion n2, Posicion c) {
        // Punto en el segmento al cual se calculara la distancia
        // iniciamos en uno de los extremos
        Posicion p = new Posicion(n1);

        // Para prevenir una division por cero se calcula primero el demoninador de
        // la division. (Se puede dar si A y B son el mismo punto).
        // Podria substituirse por [self modulo2:A a:B]
        double denominador = (n2.getX() - n1.getX()) * (n2.getX() - n1.getX()) + (n2.getY() - n1.getY()) * (n2.getY() - n1.getY());

        if (denominador != 0) {
            // Se calcula el parametro, que indica la posicion del punto P en la recta
            // del segmento
            double u = ((c.getX() - n1.getX()) * (n2.getX() - n1.getX()) + (c.getY() - n1.getY()) * (n2.getY() - n1.getY())) / denominador;
            // Si u esta en el intervalo [0,1], el punto P pertenece al segmento
            if (u > 0.0 && u < 1.0) {
                p = p.setPosicion(n1.getX() + u * (n2.getX() - n1.getX()), n1.getY() + u * (n2.getY() - n1.getY()));
            } // Si P no pertenece al segmento se toma uno de los extremos para calcular
            // la distancia. Si u < 0 el extremo es n1. Si u >=1 el extremos es n2.
            else {
                if (u >= 1.0) {
                    p = new Posicion(n2);
                }
            }
        }
        // Se devuelve la distancia entre el punto C y el punto P calculado.
        return p.distancia(c);
    }

    public static double getDistanciaJugadorMasCercaAlSegmento(Posicion[] list, Posicion n1, Posicion n2) {
        int jugador = -1;
        double distancia = 0;
        for (int i = 0; i < list.length; i++) {
            if (jugador == -1 || distancia > distanciaAlSegmento(n1, n2, list[i])) {
                jugador = i;
                distancia = distanciaAlSegmento(n1, n2, list[i]);
            }

        }
        return distancia;
    }

    public static Balon getSiguienteUbicacion(Posicion balon1, Posicion balon2, double altura, double dz, boolean suelo) {
        double balonDx = balon2.getX() - balon1.getX();
        double balonDy = balon2.getY() - balon1.getY();
        double balonDz = dz;
        double alturaBalon = altura;

        Posicion balon = new Posicion(balon2);

        if (!suelo && alturaBalon == 0 && balonDz >= 0 && balonDz < Constantes.G * 3) {//condicion para que se arrastre
            suelo = true;
        }
        if (suelo) {
            balonDx = balonDx * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
            balonDy = balonDy * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
        } else {
            alturaBalon = redondeaMultiplo(alturaBalon + balonDz, Constantes.G);
            balonDz = redondeaMultiplo(balonDz - Constantes.G, Constantes.G);
            balonDx = balonDx * Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
            balonDy = balonDy * Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
            if (alturaBalon == 0) {
                balonDz = (-balonDz - Constantes.G) * Constantes.FACTOR_DISMINUCION_ALTURA_BALON_REBOTE;
                balonDz = redondeaMultiplo(balonDz, Constantes.G);
            }
        }
        balon = balon.moverPosicion(balonDx, balonDy);

        return new Balon(balon, alturaBalon, balonDz, suelo);
    }

    private static double redondeaMultiplo(double valor, double divisor) {
        return Math.round(valor / divisor) * divisor;
    }

    public static Posicion Interseccion(Posicion n1, Posicion n2, Posicion m1, Posicion m2) {
        double a1 = n1.getY() - n2.getY();
        double b1 = n2.getX() - n1.getX();
        double c1 = n1.getX() * n2.getY() - n2.getX() * n1.getY();

        double a2 = m1.getY() - m2.getY();
        double b2 = m2.getX() - m1.getX();
        double c2 = m1.getX() * m2.getY() - m2.getX() * m1.getY();

        double d = a1 * b2 - a2 * b1;
        double d1 = c1 * b2 - c2 * b1;
        double d2 = a1 * c2 - a2 * c1;

        if (d != 0) {
            return new Posicion(-1 * (d1 / d), -1 * (d2 / d));
        } else {
            return null;
        }
    }
    private final static double MITAD_ANCHO = Constantes.ANCHO_CAMPO_JUEGO / 2;
    private final static double MITAD_LARGO = Constantes.LARGO_CAMPO_JUEGO / 2;

    public static boolean dentroCampo(Posicion p) {
        return (p.getX() >= -MITAD_ANCHO && p.getX() <= MITAD_ANCHO &&
                p.getY() >= -MITAD_LARGO && p.getY() <= MITAD_LARGO);
    }

    public static double getAnguloOptimo(Posicion b, Posicion destino, int jugador) {
        double anguloOptimo = 20;
        double distancia = b.distancia(destino);

        if (distancia > 25) {
            anguloOptimo = 30;
        } else if (distancia < 8) {
            anguloOptimo = 10;
        }

        return anguloOptimo;
    }

    public static int iteracionesCruzarBalon(ArrayList<Balon> posiciones, Posicion posicionJugador, int jugador) {
        double velocidadJugador = new TacticaDetalleTricolor().getJugadores()[jugador].getVelocidad();
        int i = 0;
        boolean found = false;
        double alturaControl = Constantes.ALTURA_CONTROL_BALON;
        double distanciaControl = Constantes.DISTANCIA_CONTROL_BALON;
        if (new TacticaDetalleTricolor().getJugadores()[jugador].esPortero()) {
            alturaControl = Constantes.ALTO_ARCO;
            distanciaControl = Constantes.DISTANCIA_CONTROL_BALON_PORTERO;
        }
        Balon p = null;
        while (!found && (i < ITERACIONES_CRUZAR_BALON)) {
            p = posiciones.get(i);
            if ((p.posicion.distancia(posicionJugador) <= ((Constantes.getVelocidad(velocidadJugador) * (i + 1)) + distanciaControl)) && p.altura <= alturaControl) {
                found = true;
            } else {
                i++;
            }
        }
        if (!found) {
            i = -1;
        }
        return i;
    }
}
